
package com.studiofortress.sf.structure;

import com.studiofortress.sf.graphics.display.ControlEvent;
import com.studiofortress.sf.util.collections.CachingHashSet;
import com.studiofortress.sf.util.collections.CallbackIterable;
import com.studiofortress.sf.util.collections.CallbackIterator;
import com.studiofortress.sf.util.collections.CallbackPartialIterator;
import java.util.Collection;
import java.util.Set;
import java.util.TreeMap;

/**
 * Stores Actors in a collection sorted by their number. Actors with a high
 * number are stored after those with a low number.
 * 
 * @author Joseph Lenton
 */
class SortedActors<A extends Actor> implements CallbackIterable<A>
{
    private final TreeMap<Integer, CachingHashSet<A>> actors;
    
    /**
     * Trivial constructor.
     */
    SortedActors()
    {
        actors = new TreeMap<Integer, CachingHashSet<A>>();
    }
    
    /**
     * Iterates over all of the actors in this SortedActors in order, from the
     * actors at the bottom to those at the top.
     * @param callback The callback object to use for iterating, cannot be null.
     */
    public void iterate(final CallbackIterator<A> callback)
    {
        if ( callback == null ) {
            throw new IllegalArgumentException("The given callback cannot be null.");
        }

        for ( CachingHashSet<A> set : actors.values() ) {
            set.iterate( callback );
        }
    }

    public void iteratePartial(final CallbackPartialIterator<A> callback)
    {
        if ( callback == null ) {
            throw new IllegalArgumentException("The given callback cannot be null.");
        }

        callback.startIteration();
        for ( CachingHashSet<A> set : actors.values() ) {
            if ( callback.isIterating() ) {
                set.iteratePartial( callback );
            } else {
                return;
            }
        }
    }

    /**
     * Iterates over this SortedActors in reverse order.
     * @param callback The callback iterator which contains the event to be used.
     */
    <E extends ControlEvent> void iterateControlCallback(final ControlEventCallbackPartialIterator<A, E> callback)
    {
        if ( callback == null ) {
            throw new IllegalArgumentException("The given callback cannot be null.");
        }

        // descending map reverses the order
        for ( CachingHashSet<A> set : actors.descendingMap().values() ) {
            if ( callback.isIterating() ) {
                set.iteratePartial( callback );
            } else {
                return;
            }
        }
    }
    
    /**
     * Adds this Actor to be stored at the given orderNum position.
     * If the Actor is already stored at a different orderNum then it will be
     * added twice.
     * @param actor The Actor to store.
     * @param orderNum The order which the Actor is stored at.
     */
    void add(final A actor, final int orderNum)
    {
        CachingHashSet<A> actorSet = actors.get( orderNum );

        if (actorSet == null) {
            actorSet = new CachingHashSet<A>();
            actors.put( orderNum, actorSet );
        }
        
        actorSet.add( actor );
    }
    
    /**
     * Removes this Actor, if found, from the given orderNum.
     * If the Actor is stored at a different orderNum then it is not removed.
     * @param actor The Actor to remove.
     * @param orderNum Where to try to remove it from.
     * @return True if the Actor was found and removed, otherwise false.
     */
    boolean remove(final A actor, final int orderNum)
    {
        final Set<A> actorSet = actors.get( orderNum );

        if ( actorSet != null ) {
            return actorSet.remove( actor );
        }

        return false;
    }
    
    /**
     * Removes all currently stored Actors from this collection.
     */
    void clear()
    {
        actors.clear();
    }
    
    /**
     * @return A collection containing each layer of actors in the order they are stored in this collection.
     */
    Collection<CachingHashSet<A>> getActorLayers()
    {
        return actors.values();
    }
}
